/**
 *
 *
 * \file MaCI.i
 * \brief Python bindings for following by Tapio Taipalus <tapio.taipalus@tkk.fi>
 * \brief Describes the methods and types common for all MaCI interfaces "MaCI.hpp".
 * \author Antti Maula <antti.maula@tkk.fi>
 */
%include std_vector.i
%include std_string.i
%include std_map.i
//%include "MaCIError.i"
//%include "./MaCICtrl/MaCICtrlServer.i"


%{
#include <string>
#include <vector>
#include <map>
#include "ownutils.h"
#include "MaCICtrlServer.hpp"
#include "MaCICtrlClient.hpp"
#include "gimiutils.h"
#include "MaCIError.hpp"
#include "MaCI.hpp"
#include "gimi.h"
%}

/// Interface offset value.
#define MACI_CLIENT_INTERFACE_ID_OFFSET 5000

/// Macro to construct a Client Interface ID by Service ID.
#define MACI_SERVICEID2CLIENTID(x) ((x)+MACI_CLIENT_INTERFACE_ID_OFFSET)


/** MaCI - Machine Control Interface
 *  
 * MaCI namespace contains all the classes belonging to the MaCI
 * Machine control interface.
 *
 */
namespace MaCI {
  namespace Alarm {
    class CAlarmServer;
  }

  /** Construct a static client name based on binary environment.
   *
   * This function returns a name which is condensed from following information:
   * \li hostid (from gethostid())
   * \li current working directory (from getcwd())
   * \li current uid+gid+euid+egid (from getuid(),getgid(),geteuid(),getegid())
   * \li optional user given string
   * 
   * If this name is used for GIMIname, the application will get the
   * same name from start to start, allowing the GIMI resubscribe
   * mechanism to work as expected.
   *
   * @param[in] aUserKey        User given string to append to
   *                            environment before condensing. 
   *                            (arbitrary length)
   * @return                    GIMnet compatible name which is
   *                            consistent from call to call.
   */
  std::string GetStaticClientName(const std::string &aUserKey = "");
  


  /** Common structure for identifying message source.
   * 
   * This is a structure identifying a message source. Use this for
   * example, when you need the minimum information possible to
   * identify a certain message source, like; when you need to reply
   * to some message.
   *
   * \see EnableSynchronousMessageReply
   * \see DisableSynchronousMessageReply
   * \see SendSynchronousMessageReply
   * \see ReceiveSynchronousMessageReply
   */
  struct SMessageSource
  {

    /** Constructor initializing all members by GIMI message.
     *
     */
    SMessageSource(const gimi::GIMIMessage &aMsg);

    /** Constructor initializing all members by values
     */
    SMessageSource(const int aGimNetID = 0,
                   const int aMajorNumber = 0,
                   const int aMinorNumber = 0,
                   const int aMessageID = 0);
 
    /** Print contents.
     *
     * This function prints container contents through dPrint.
     * 
     * @param[in] level         dPrint level to use for printing.
     */
    void Print(const int level) const;

    /** Convert contents to human-readable string.
     *
     * @param[in] aIncludeMajorMinor Include major minor numbers in print.
     * @return                  Contents converted to string for 
     *                          displaying.
     */
    std::string ToString(bool aIncludeMajorMinor = false) const;
    

    int gimnetID;     ///< GIMnet Id of source.
    int majorNumber;  ///< Major number of received message (target in fact).
    int minorNumber;  ///< Minor number of received message (target in fact).
    int messageID;    ///< MessageID of received message.
  };


  /** MaCI Server/Client base class
   *
   * Base class for a MaCI Server/Client module. All MaCI
   * Server/Client interfaces must derive from this class to allow for
   * maximum consistency between different MaCI modules.
   *
   */
  class CMaCI
  {
  public:

    /** Construct.
     *
     * This is the constructor for Server side implementations of MaCI
     * interface.
     *
     * Constructor takes a pointer to common CMaCICtrlServer instance,
     * which is used as a backend for communicating MaCI specific
     * parameters. The GIMI pointer is also taken from the
     * CMaCICtrlServer so the same GIMI is used inside the interface
     * and the CMaCICtrlServer.
     *
     * @param[in] aMaCICtrlServer  Pointer to MaCICtrl instance
     * @param[in] aInterfaceMajor  MajorID of this interface
     * @param[in] aInterfaceMinor  MinorID of this interface. If this is
     *                             negative, next available minor will be probed.
     * @param[in] aInterfaceInstanceName Name of interface instance name. For example,
     *                             if this is instance of interface 'Ranging', 
     *                             the InstanceName could be 'Laser'. This can also
     *                             be set by calling 'SetInterfaceInstanceName()'.
     * @param[in] aUseStandaloneClientID If this is set to \b true,
     *                             the CMaCI class will change the given MajorID 
     *                             to the separate ClientID range, using the 
     *                             OFFSET value set by MACI_CLIENT_INTERFACE_ID_OFFSET.
     *                             Remember that using this method requires the Service
     *                             part to also send replies to major number specified
     *                             by the offset. As this is a new feature, standalone
     *                             clientID defaults to FALSE, meaning the Client interface
     *                             uses the same Major value as the server side.
     */
    CMaCI(MaCI::MaCICtrl::CMaCICtrlServer *aMaCICtrlServer,
	  const int aInterfaceMajor, 
	  const int aInterfaceMinor = -1,
          const std::string &aInterfaceInstanceName = "",
          const bool aUseStandaloneClientID = false);


    /** Construct.
     *
     * This is the constructor for Client side implementations of MaCI
     * interface.
     *
     * Constructor takes a pointer to common GIMI instance, which is
     * used as a backend for communicating. If this pointer is NULL,
     * the 'ConnectGIMnet()' function must be called before using any
     * other interface function.
     *
     * @param[in] aGIMIPtr         Pointer to GIMI instance, or NULL if 
     *                             connected later.
     * @param[in] aInterfaceMajor  MajorID of this interface
     * @param[in] aInterfaceMinor  MinorID of this interface. If this is
     *                             negative, next available minor will be probed.
     *
     * @param[in] aUseStandaloneClientID If this is set to \b true,
     *                             the CMaCI class will change the given MajorID 
     *                             to the separate ClientID range, using the 
     *                             OFFSET value set by MACI_CLIENT_INTERFACE_ID_OFFSET.
     *                             Remember that using this method requires the Service
     *                             part to also send replies to major number specified
     *                             by the offset. As this is a new feature, standalone
     *                             clientID defaults to FALSE, meaning the Client interface
     *                             uses the same Major value as the server side.
     */
    CMaCI(gimi::GIMI *aGIMIPtr,
	  const int aInterfaceMajor, 
	  const int aInterfaceMinor = -1,
          const bool aUseStandaloneClientID = false);
        
    
    /** Destructor.
     */
    virtual ~CMaCI();
    

    /** Open interface.
     * 
     * This function carries out MaCI specific Open procedures, and
     * the calles the derived classes 'DoOpen()' function to carry out
     * derived classes open procedures. This function doesn't take
     * parameters, as it assumes all necessary settings are previously
     * set. 
     *
     * This opens the interface by registering needed GIMI parameters
     * and by checking whether the requested service really exists or
     * not. If everything is initialized OK, the function should
     * return KMaCIOK. In case there are any errors, and appropriate
     * value from the type EMaCIError should be selected.
     *
     * \see EMaCIError
     * \see SetDefaultTarget
     * \see SetInterfaceInstanceName
     *
     * @return                  Value of type EMaCIError describing
     *                          the derived classes DoOpen() functions 
     *                          status.
     */
    MaCI::EMaCIError Open();


    /** Close interface.
     *
     * This function carries out derived classes 'DoClose()' function
     * to carry out derived class specific close procedures and then
     * carries out base class specific close procedures.
     *
     * @return                  Value of type EMaCIError describing
     *                          the derived classes DoClose() functions 
     *                          status.
     */
    MaCI::EMaCIError Close();


    /** Create new internal GIMI instance and attempt to connect it to
     * GIMnet.
     *
     * This function creates a new internal GIMI instance and uses it
     * for connecting to the GIMnet. If this function is called, any
     * previous non-internal GIMI pointer stored to this class
     * instance is overridden with new independent GIMI instance.
     *
     * \note As it is possible to share the internal GIMI instance
     * with other instances, application developers must consider the
     * object lifetime properties of the GIMI-owner class
     * instance. Because the internal instance is owned by this class
     * instance, it will be automatically disconnected and freed when
     * the owning instance is destroyed. Any clients using the
     * destroyed GIMI will most probably lead to a crash.
     *
     * @param[in] aHostname     Hostname of the machine where GIMnetAP
     *                          is running.
     * @param[in] aPort         Port of the GIMnetAP.
     * @param[in] aName         Own name for this instance. If this 
     *                          is left empty or is unspecified,
     *                          anonymous entry is automatically
     *                          generated by GIMI.
     * @return                  KMaCIOK on success, other EMaCIError
     *                          values on error situations.
     */
    MaCI::EMaCIError CreateGIMnetConnection(const std::string &aHostname,
                                      const unsigned int &aPort,
                                      const std::string &aName = "");
    
    
    /** Close and Destroy internal GIMI instance if such exists.
     *
     * This function disconnects and destroys the preconnected
     * internal GIMI instance. (Initialized previously with function
     * CreateGIMnetConnection())
     *
     * @return                  KMaCIOK on success, other EMaCIError
     *                          values on error situations.
     */
    MaCI::EMaCIError DestroyGIMnetConnection(void);
    
    
    /** Set MaCICtrlServer instance to use.
     *
     * This call only changes the active MaCICtrlServer instance. 
     * If you have registered services before calling this function,
     * those will NOT be listed in the new MaCICtrlServer anymore.
     * 
     * @param[in] aMaCICtrlServer Pointer to MaCICtrlServer to use.
     */
    //void SetMaCICtrlServer(MaCI::MaCICtrl::CMaCICtrlServer *aMaCICtrlServer);


    /** Assign default target/source for this MaCI interface.
     *
     * Assigns a default target name. This name will be used for
     * Service subscribtions and GIMI Redirection buffer
     * creation. This function can be called anytime during executing,
     * as it only stores a new name inside the class instance.
     *
     * @param[in] aDefaultTarget GIMnet name to use as default target.
     */
    void SetDefaultTarget(const std::string &aDefaultTarget);

    
    /** Assign default target/source for this MaCI interface by GIMnetID.    
     *
     * This function takes the target information as GIMnetID.
     *
     * \note This function requires the GIMI backend to be connected,
     * as the functionality depends on external information.
     *
     * \overload 
     *
     * @param[in] aDefaultTargetId   Target ID to set.
     * @return                  'true' if name was succesfully found
     *                          for given ID, otherwise false.
     */
    bool SetDefaultTarget(const unsigned int aDefaultTargetId);


    /** Assign default target by MaCI Service Locator.
     *
     * Assign the default target using a MaCI Service Locator. The
     * locator is evaluated right away and on succesfull call, this
     * function will change the current value of 'iDefaultTarget' as
     * well as the current value of 'iInterfaceMinor'. 
     *
     * This function is implemented so, that it first queries the 
     * GIMI service table, and them passes the entry array to the
     * 'next' SetDefaultTarget function.
     *
     * \note This function requires the GIMI backend to be connected,
     * as the functionality depends on external information.
     *
     * \note The service must be present on the GIMnet at the time of
     * this call, otherwise it cannot be identified.
     *
     * \note This function will take atleast half the timeout given,
     * because the GIMI service discovery doesn't complete before
     * timeout expires. If you are initializing multiple services,
     * it's highly recommended to use the other 'SetDefaultTarget'
     * functions which use previously fetched data.
     *
     * \note This function MUST be called before calling Open(),
     * because otherwise incorrect Minor number will be used during
     * initialization!
     *
     * @param[in] aMaCISL       MaCISL expression to evaluate.
     * @param[in] aTimeout_ms   Timeout to wait for operation to complete.
     */
    bool SetDefaultTarget(const MaCI::MaCICtrl::SMaCISL &aMaCISL, 
                          const unsigned int aTimeout_ms = 2000);
    
    

    /** Assign default target by MaCI Service Locator from group of
     * existing GIMI services.
     *
     * Assign the default target using a MaCI Service Locator. The
     * locator is evaluated right away and on succesfull call, this
     * function will change the current value of 'iDefaultTarget' as
     * well as the current value of 'iInterfaceMinor'. Difference to
     * function 'bool SetDefaultTarget(const MaCICtrl::SMaCISL
     * &aMaCISL, const unsigned int aTimeout_ms = 2000);' is that this
     * function doesn't do GIMI service discovery. This save a lot of
     * time, as the MaCI discovery is very fast.
     *
     * \note This function requires the GIMI backend to be connected,
     * as the functionality depends on external information.
     *
     * \note The service must be present on the GIMnet at the time of
     * this call, otherwise it cannot be identified.
     *
     * @param[in] aMaCISL       MaCISL expression to evaluate.
     * @param[in] aServiceList  GIMI Servicearray. All MaCICtrl services 
     *                          on this list are probed. The list can be 
     *                          queried with MaCICtrlClient or with GIMI 
     *                          directly.
     * @param[in] aTimeout_ms   Timeout to wait for operation to complete.
     */
    bool SetDefaultTarget(const MaCI::MaCICtrl::SMaCISL &aMaCISL, 
                          const gimi::t_serviceList &aServiceList,
                          const unsigned int aTimeout_ms = 2000);


    /** Assign default target by MaCI Service Locator from a group of
     * already queried MaCI Service entries.
     *
     * Assign the default target using a MaCI Service Locator. The
     * locator is evaluated right away and on succesfull call, this
     * function will change the current value of 'iDefaultTarget' as
     * well as the current value of 'iInterfaceMinor'. Difference to
     * function 'bool SetDefaultTarget(const MaCICtrl::SMaCISL
     * &aMaCISL, const unsigned int aTimeout_ms = 2000);' is that this
     * function doesn't do GIMI service discovery OR MaCICtrl
     * query. All information is provided on command line. This
     * function doesn't need any connections, as all information is
     * provided as parameters. This is the fastest function available
     * for setting the Default target by MaCISL.
     *
     * @param[in] aMaCISL       MaCISL expression to evaluate.
     * @param[in] aServices     List of available MaCI services. The list can
     *                          be queried with MaCICtrlClient.
     */
    bool SetDefaultTarget(const MaCI::MaCICtrl::SMaCISL &aMaCISL, 
                          const MaCI::MaCICtrl::TServiceEntryArray &aServices);
    

    /** Set static link delay (For operation over delayed links)
     *
     * This function sets the default Static link delay. Meaning
     * of this delay is to allow operation over links with delays
     * longer than default timeouts allow. All default timeouts are
     * incremented with this value, so all operations are allowed
     * to run longer before timing out.
     *
     * @param[in] aDelay_ms     Static link delay in milliseconds in
     *                          one direction.
     */
    void SetStaticLinkDelay(const unsigned int aDelay_ms);


    /** Set the MaCI group name where this Interface belongs to.
     *
     * This function is a convenience function, wrapping the
     * call to underlying MaCICtrlServer instance.
     *
     * \note Calling this function is equal to:\n
     * GetMaCICtrlServer()->SetGroupName(aGroupName);
     *
     * \note As this function modifies the underlying MaCICtrlServer
     * instance, the change is global to all modules bound to this
     * MaCICtrlServer instance.
     *
     * @param[in] aGroupName Name of the Group to assign.
     * @return                'true' if binding was succesfull (valid name)
     *                        otherwise 'false' on failure.
     */
    bool SetGroupName(const std::string &aGroupName);
    

    /** Set interface access parameters for server side.
     *
     * This functions sets up authentication requirements for this
     * interface instance. The function call acts as a wrapper for the
     * MaCICtrlServer, providing the current values of \p
     * iInterfaceMajor and \p iInterfaceMinor as parameters.
     *
     * \note This function modifies the MaCICtrlServer instance, hence
     * its probably only usefull on the server side of the interface.
     *
     * @param[in] aAuth         Reference to TAuthentication entry containing
     *                          authentication information for the interface.
     * @param[in] aMaxAccess    Maximum number of simultaneous accesses to this interface.
     *                          Negative value stands for 'unlimited'. 
     * @param[in] aAccessTimeout_ms Number of milliseconds to keep the 
     *                          access valid. Negative value stands for 'Forever'.
     *                          Keeping this !unlimited allows old entries to be 
     *                          removed, instead of being stored forever.
     */
    void SetServerInterfaceAuthentication(const MaCI::MaCICtrl::TAuthentication &aAuth,
                                          const int aMaxAccess,
                                          const int aAccessTimeout_ms);
    

    /** Set interface access parameters for client side.
     *
     * This function stores authentication information to be used by
     * the ValidateInterfaceAccess() function.     
     
     * \note This function stores information which is only useful on
     * the client side of the interface (or on interface requiring
     * client role for some other service)
     *
     * @param[in] aAuth         Reference to TAuthentication entry containing
     *                          authentication information for the interface.
     */
    void SetClientInterfaceAuthentication(const MaCI::MaCICtrl::TAuthentication &aAuth);


    /** Set the Interface instance name.
     *
     * Set this name to make this instance unique among others in the
     * namespace formed by MaCIGroup and Interface type. For example
     * 'J2B2.Image.LeftCamera', where the 'LeftCamera' part is the
     * Instance name.
     *
     * @param[in] aInstanceName Instance name to set.
     */
    void SetInterfaceInstanceName(const std::string &aInstanceName) {
      iInterfaceInstanceName = aInstanceName;
    }


    /** Assign the current activity state of this interface instance.
     *
     * @param[in] aActiveState  Set the activity state to this.
     * @return                  Previous activity state.
     */
    bool SetActive(const bool aActiveState) {
      const bool previous_state = iIsActive;
      iIsActive = aActiveState;
      return previous_state;
    }


    /** Attempts to validate access to the service by using the 
     * preset authentication parameters.
     *
     * This function sends the stored Authentication information entry
     * to server side of MaCICtrl interface. The provided 'aAccess'
     * reference is then filled (if succesfull) with access
     * information concerning the target service. 
     *
     * \note This function sends request to remote side, so it is
     * probable usable only on the client side. (or on a service
     * requiring client role for some other service)
     *
     * \note If the RequestInterfaceAccess() function is not
     * called before this function, the validation will be attempted
     * with default TAuthentication entry.
     *
     * @param[out] aAccess      Reference to TAccess to be filled with
     *                          information about acquired access.
     * @return                  'KMaCIOK' when access was succesfully read and stored.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError ValidateClientInterfaceAuthentication(MaCI::MaCICtrl::TAccess &aAccess);


    /** Enable Built-In Alarm interface.
     *
     * This function constructs a new CAlarmServer interface instance
     * (if not already constructed). The Alarm interface will show as
     * normal Alarm service instance, but its service minor will have
     * a special encoding (oh dear :).
     *
     * Encoding goes as follows: The upper 16 bits (upper WORD) of the
     * Minor contains the \b major number and the lower 16 bits (lower
     * WORD) contain the minor number of the service this Alarm is
     * bound to.
     *
     * \note Please note that this scheme doesn't work if MaCI-majors
     * ever exceed 65535, or the interface in question is using a
     * minor >65535
     *
     * @return                  'KMaCIOK' if the instance was
     *                          constructed and intialized properly.
     *                          In case of any error, appropriate
     *                          EMaCIError is returned.
     */
    MaCI::EMaCIError EnableAlarmServer(void);


    /** Disable Built-In Alarm interface.
     *
     * This function cleans up the internal CAlarmServer interface
     * instance (if previously constructed), and marks the AlarmServer
     * as unset (allows reconstruction by 'EnableAlarmServer()')
     *
     * @return                  'KMaCIOK' if the instance was
     *                          deintialized and destructed properly.
     *                          In case of any error, appropriate
     *                          EMaCIError is returned.
     */
    MaCI::EMaCIError DisableAlarmServer(void);

    
    /** Return pointer to internal MaCI::CAlarmServer instance.
     *
     * This function returns a pointer to internal MaCI::CAlarmServer
     * instance. If the returned pointer is non-NULL, the value poinst
     * to an fully initialized CAlarmServer. The instance may be used
     * independently of the MaCI interface.
     *
     * \note If 'DisableAlarmServer()' is called for the MaCI
     * instance, the instance that the pointer returned by this
     * function points to will become invalid. Calling any interface
     * functions after 'DisableAlarmServer()' call will probably cause
     * a software crash.
     *
     * \see EnableAlarmServer
     * \see DisableAlarmServer
     *
     * @return                  Pointer to MaCI internal Alarm::CAlarmServer 
     *                          instance, or NULL if the interface is not
     *                          enabled (See 'EnableAlarmServer()')
     */
    inline Alarm::CAlarmServer *GetAlarmServerPtr(void) const;


    /** Return pointer to currently set MaCICtrlServer instance.
     *
     * This function returns pointer to currently set MaCICtrl server
     * instance. If the server is not set (Client mode) this function
     * returns NULL.
     *
     * @return                  Pointer to currently set MaCICtrlServer,
     *                          or NULL if not set (Client mode)
     */
    MaCI::MaCICtrl::CMaCICtrlServer *GetMaCICtrlServerPtr(void) const;


    /** Returns pointer to currently set GIMI instance.
     *
     * This function returns a pointer to currently set GIMI instance.
     *
     * \note In case of Server mode, the GIMI instance is infact fetched from
     * the MaCICtrlServer interface.
     * 
     * @return                  Pointer to currently used GIMI interface.
     */
    gimi::GIMI *GetGIMIPtr(void) const;

    
    /** Return current default target name for this MaCI interface.
     * 
     * @return                  Currently assigned default
     *                          target name for this MaCI instance.
     */
    const std::string &GetDefaultTarget(void) const;

    
    /** Return currently (succesfully) assigned default target MaCISL.
     *
     * This function returns the default target MaCISL, if such was
     * given.
     *
     * @return                  Returns the currently assigned MaCISL
     *                          entry. If the entry is unset,
     *                          the returned structure is invalid.
     *                          This can be tested by calling function
     *                          'MaCICtrl::SMaCISL::IsValidFQMaCISL()'
     *                          from the returned entry.
     */ 
    const MaCI::MaCICtrl::SMaCISL &GetDefaultTargetMaCISL(void) const;


    /** Return the number of subsribers currently connected to this
     * service instance.
     *
     * This function returns the number of active subscribers
     * subscribed to the provided interface of this interface
     * instance. If this interface doesn't have a provided interface,
     * negative value is returned. Otherwise the current number of
     * active subscribers is returned (which can ofcourse be zero too)
     *
     * \note This function is just a wrapper for the GIMIs
     * 'getSubscriberCount' function, using the interface specific
     * Major and Minor as parameters.
     *
     * @return                  Number of subscribers to this service.
     *                          If there is no subscribers, this function
     *                          returns zero. Negative value is returned
     *                          on any error, for example; when
     *                          there is no provided interface for
     *                          the currently assigned interface number.
     * 
     */
    int GetInterfaceSubscriberCount(void) const;


    /** Return Interface name.
     *
     * Returns the name of this Interface.
     *
     * @return                  Interface name. If the Interface name is not 
     *                          set, zero length string is returned.
     */
    std::string GetInterfaceName(void) const;


    /** Return Interface Instance name.
     * 
     * Returns the name of instance using this interface. For example,
     * instance of Interface 'Ranging' could have instance name
     * 'LaserSICK'.
     * 
     * @return                  Name of interface instance. If the interface
     *                          instance name is not set, zero length string is
     *                          returned.
     */
    std::string GetInterfaceInstanceName(void) const;


    /** Returns the MaCIGroup name currently set for this instance.
     *
     * This function returns the currently set MaCIGroup name for the
     * instance. If the name is unset, string is empty.
     *
     * @return                  Currently set MaCI Group name. (like; J2B2)
     *                          Empty string if not set.
     */
    std::string GetGroupName(void) const;


    /** Returns the currently set Static link delay.
     *
     * This function returns the currently set Static link delay for
     * this instance.
     *
     * @return                  Currently set static link delay.
     */
    const unsigned int GetStaticLinkDelay(void) const;


    /** Is the GIMnet connection valid and alive.
     *
     * This function returns 'true' if the underlying GIMI instance is
     * still correctly connected to GIMnet. This value is fetched
     * directly from 'GIMI::isConnected()' method.
     *
     * \note This call corresponds to call:
     * GetGIMIPtr()->isConnected();
     *
     */
    bool IsGIMnetConnectionValid(void) const;


    /** Returns the activity state of this interface instance.
     * 
     * This value is updated by the Open() function with respect to
     * value returned by the DoOpen() function of the derived class.
     * If the DoOpen() function returns 'KMaCIOK', the activity state
     * is marked as 'true', otherwise 'false'. Also, when calling
     * 'Close()', the result of 'DoClose()' updates the status to
     * 'false' when the DoClose() returns KMaCIOK.
     *
     * @return 'true' if the interface is active, 'false' otherwise.
     */
    inline bool IsActive(void) const;

  protected:
    ///////////////////////////////////////////////////////////////////////////
    ////////////// Functions for derived classes.  ////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    /** Derived class Implementation for 'Open interface'.
     *
     * All MaCI derived classes must implement the 'DoOpen()' function
     * to carry out their own procedures which should be done
     * on 'Open'.
     *
     * This opens the interface by registering needed GIMI parameters
     * and by checking whether the requested service really exists or
     * not. If everything is initialized OK, the function should
     * return KMaCIOK. In case there are any errors, and appropriate
     * value from the type EMaCIError should be selected.
     *
     * \see EMaCIError
     *
     * @return                  Value of type EMaCIError describing
     *                          the DoOpen() status.
     */
    virtual MaCI::EMaCIError DoOpen() = 0;


    /** Derived class Implementation for 'Close interface'.
     *
     * All MaCI derived classes must implement the 'DoClose()' function
     * to carry out their own procedures which should be done
     * on 'Close'.
     *
     * This closes the interface. If everything is closed down OK, the
     * function should return KMaCIOK. In case there are any errors,
     * and appropriate value from the type EMaCIError should be
     * selected.
     *
     * \see EMaCIError
     *
     * @return                  Value of type EMaCIError describing
     *                          the DoClose() status.
     */
    virtual MaCI::EMaCIError DoClose() = 0;


    /** Get correct timeout value for defined user timeout (static
     * link delay applied)
     *
     * Returns a Timeout value incremented with the StaticLinkDelay.
     * Use this function on ALL timeout commands in your software 
     * to allow it to work over long links too.
     * 
     * @param[in] aTimeout      Timeout value to recompute
     * @return                  Recomputed timeout value
     *
     */
    inline int TimeoutValue(const int aTimeout) {
      return (iStaticLinkDelay + aTimeout);
    }

    
    /** Register provided service for this interface.
     *
     * This function is a simple wrapper for GIMI register. It only
     * calls the 'addProvidedService' function with the 
     * device major and minor types. (iInterfaceMajor, iInterfaceMinor)
     * 
     * \note This function also registers the service to MaCICtrlServer,
     * so if you choose NOT to use this function, remember to call
     * the AddGroupService() manually from the MaCICtrlServer interface.
     *
     * @param[in] aDescription  Description for this service.
     * @return                  'true' when the service was succesfully
     *                          registered. 'false' is returned if the
     *                          service was already registered.
     */
    bool RegisterProvidedService(const std::string &aDescription);


    /** Unregister provided service for this interface.
     *
     * This function is a simple wrapper for GIMI register. It only
     * calls the 'removeProvidedService' function with the 
     * device major and minor types. (iInterfaceMajor, iInterfaceMinor)
     *
     * @return                  'true' when the service was succesfully
     *                          unregistered. 'false' is returned if the
     *                          service was not previously registered.
     */
    bool UnregisterProvidedService(void);


    /** Register accepted service for this interface.
     *
     * This function is a simple wrapper for GIMI register. It only
     * calls the 'addAcceptedService' function with the 
     * device major and minor types. (iInterfaceMajor, iInterfaceMinor)
     * Also, the gimi::addRedirection is called with the iRedirectionBufferId
     * value initialized by class constructor.
     * 
     * \note This function also registers the service to MaCICtrlServer,
     * so if you choose NOT to use this function, remember to call
     * the AddGroupService() manually from the MaCICtrlServer interface.
     *
     * @param[in] aDescription  Description for this service.
     * @return                  'true' when the service was succesfully
     *                          registered. 'false' is returned if the
     *                          service was already registered.
     */
    bool RegisterAcceptedService(const std::string aDescription);


    /** Unregister accepted service for this interface.
     *
     * This function is a simple wrapper for GIMI register. It only
     * calls the 'removeAcceptedService' function with the 
     * device major and minor types. (iInterfaceMajor, iInterfaceMinor)
     * Also, redirection is removed by gimi::removeRedirection
     *
     * @return                  'true' when the service was succesfully
     *                          unregistered. 'false' is returned if the
     *                          service was not previously registered.
     */
    bool UnregisterAcceptedService(void);


    /** Receive messages for this interface instance.
     *
     * This function acts as a simple wrapper for the GIMIs
     * receiveMessage function using the variables \p iInterfaceMajor,
     * \p iInterfaceMinor and \p iRedirectionBufferId for the call.
     *
     * This is a helper function, and its use is not compulsory in any
     * way. 
     *
     * \note If you don't use this function, you STILL MUST USE THE
     * REDIRECTIONBUFFERID because otherwise your interface doesn't
     * work correctly when multiple sessions share the same GIMI instance!
     *
     * @param[out] aMsg         GIMI message to fill in when message is
     *                          succesfully received within timeout.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait until 
     *                          operation fails for timeout.
     * @return                  'KMaCIOK' when message was succesfully received
     *                          within the specified timeout. Other values
     *                          when there was a communication layer error
     *                          (See desription of type EMaCIError)
     */
    MaCI::EMaCIError ReceiveInterfaceMessage(gimi::GIMIMessage &aMsg, 
                                       const int aTimeout_ms);
    

    /** Receive message to this interface, converting it to correct
     * type.
     *
     * This function is identical to previous version of
     * ReceiveInterfaceMessage(), \b except that this function
     * does the DataType conversion online. For example, you can call this function directly like:
     * \code
     * CDummyData dd;
     * SMessageSource ms;
     * ReceiveInterfaceMessage(dd, ms, 1000);
     * \endcode
     *
     * And the MaCI will take care of the conversion for you! This is
     * implemented as template function, so the converted type must
     * implement atleast the following method: 
     * \code
     * bool DecodeFrom(gim::binbag::CBinBag *aBinBag);
     * \endcode
     *
     * \note This function also automatically checks for access, 
     *
     * \overload
     *
     * @param[out] aData        Type-converted data element output.
     * @param[out] aSource      Source information for the received message.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait for a message.
     * @return                  'KMaCIOK' when message was succesfully received.
     *                          Other values when there was an error 
     *                          (See desription of type EMaCIError)
     */
    template <class T> MaCI::EMaCIError ReceiveInterfaceMessage(T &aMsg, MaCI::SMessageSource &aSource, const int aTimeout_ms);
    
    
    /** Send message to default target of this interface.
     *
     * This function uses GIMIs send() function directly, but passes it the
     * parameters stored in the MaCI class. (major, minor, default-target)
     *
     * \note This function is probably only usable on the client side
     * of the interface. It uses the stored value of iDefaultTarget
     * (Set by SetDefaultTarget()-function). If you need to send
     * information directly to a client, it is usually
     * Client-initiated, and therefore Synchronous Reply-feature might
     * be more appropriate.
     *
     * @param[in] aBuffer       Pointer to buffer to send
     * @param[in] aBufferSize   Buffersize to send
     * @param[in] aMessageId    Optional messageID to be set on the GIMI message.
     * @return                  'KMaCIOK' when message is succesfully sent.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError SendInterfaceMessage(const char *aBuffer, const int aBufferSize,
                                    const unsigned int aMessageId = 0);


    /** Send message to default target of this interface by CMaCIData
     * container.
     *
     * Overloaded version of traditional SendInterfaceMessage, taking
     * reference to base-class CMaCIData compatible instances. These
     * instances are then queried for the BinBag instance, of which
     * the data is extraced from.
     *
     * \overload
     * 
     * @param[in] aData         Dataelement to send.
     * @param[in] aMessageId    MessageID to set for the outgoing message.
     * @return                  'KMaCIOK' when message is succesfully sent.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError SendInterfaceMessage(const MaCI::CMaCIData &aData,
                                    const unsigned int aMessageId = 0);
    

    /** Simple wrapper for gimi::sendToSubscribers() function. 
     *
     * This function uses GIMIs sendToSubscribers() function directly,
     * but passes it the parameters stored in the MaCI class. (major,
     * minor)
     *
     * \note This function is probably only usable on the server side
     * of the interface, as client side often doesn't have a
     * subsribeable interface available.
     *
     * \note The interface \b must have called the
     * RegisterProvidedService() function with proper parameters prior
     * to using this function. As if it is not called, the clients
     * cannot subscribe to the service.
     *
     * @param[in] aBuffer       Pointer to buffer to send
     * @param[in] aBufferSize   Buffersize to send
     * @param[in] aMessageID    Optional messageID to be set on the GIMI message.
     * @return                  'KMaCIOK' when message is succesfully sent.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError SendInterfaceSubscriberMessage(const char *aBuffer, 
                                                    const int aBufferSize,
                                                    const unsigned int aMessageID = 0);

    /** Set Synchronization parameters for GIMI::sendToSubscribers() call.
     *
     * This function modifies the GIMI Sync settings for the
     * Subscribed data interface. The parameters given here are fed to
     * GIMI:sendToSubscribers() calls when MaCI function
     * SendInterfaceSubscriberMessage() is called. This values default
     * to '-1' and '1000', where the -1 value on the Count will
     * disable the sync behaviour.
     * 
     * When synced messages are required, a recommended starting value
     * for aUnsyncCount is 1, which allows one unsynchronized message
     * in transit.
     *
     * @param[in] aUnsyncCount   Number of unsynced messages in transit at
     *                           any given time. (window top)
     * @param[in] aUnsyncTimeout Timeout in milliseconds until frame is dropped
     *                           as timed-out. (window bottom)
     */
    void SetInterfaceSubscriberSyncLimits(const int aUnsyncCount,
                                          const int aUnsyncTimeout);    

    /** Reply to a message, using explicit fields for reply target
     * information.
     *
     * This functions sends a reply to a previously received
     * message. The message is identified by explicit fields
     * describing the targetID, major/minor and messageID to reply to.
     *
     * For more information about using Synchronous Replies, see
     * description of function 'EnableSynchronousMessageReply()'.
     * 
     * \see EnableSynchronousMessageReply
     * 
     * @param[in] aBuffer       Pointer to buffer to send
     * @param[in] aBufferSize   Buffersize to send
     * @param[in] aTargetID     GIMnetID to send message to.
     * @param[in] aMajorNumber  Interface Major number to use.
     * @param[in] aMinorNumber  Interface Minor number to use.
     * @param[in] aMessageID    MessageID of the received message to reply for.
     * @return                  'KMaCIOK' when message is succesfully sent.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError SendSynchronousMessageReply(const char *aBuffer, const int aBufferSize,
                                           const int aTargetID,
                                           const int aMajorNumber,
                                           const int aMinorNumber,
                                           const unsigned int aMessageID);


    /** Reply to a message, using SMessageSource for reply target information.
     *
     * This functions sends a reply to a previously received
     * message. The message is identified by structure
     * 'SMessageSource'. The SMessageSource has a constructor for
     * gimi::GIMIMessage type, so its perfectly valid to give a
     * previously received gimi::GIMIMessage as source information
     * element.
     *
     * For more information about using Synchronous Replies, see
     * description of function 'EnableSynchronousMessageReply()'.
     * 
     * \see EnableSynchronousMessageReply
     * 
     * @param[in] aBuffer       Pointer to buffer to send
     * @param[in] aBufferSize   Buffersize to send
     * @param[in] aSource       Reference to original message target information. 
     *                          Its used for 
     *                          determining reply target information. As the
     *                          SMessageSource has a constructor
     *                          for GIMIMessage, it is perfectly valid
     *                          to give a GIMIMessage as parameter.
     * @return                  'KMaCIOK' when message is succesfully sent.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError SendSynchronousMessageReply(const char *aBuffer, const int aBufferSize,
                                           const MaCI::SMessageSource &aSource);

    
    /** Receive replies from Reply queue.
     *
     * This function returns a message from the reply queue identified
     * by the specified \p aMessageID.
     *
     * \note The Synchronous message feature must be enabled in order
     * for this to work. See function:
     * 'EnableSynchronousMessageReply()'.
     *
     * \see EnableSynchronousMessageReply
     *
     * @param[out] aMsg         Received message stored as GIMIMessage.
     * @param[in] aMessageID    MessageID to look for.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait for 
     *                          the reply to arrive.
     * @return                  'KMaCIOK' when correct reply is succesfully received.
     *                          Other values when there was an error 
     *                          (See desription of type EMaCIError)
     */
    MaCI::EMaCIError ReceiveSynchronousMessageReply(gimi::GIMIMessage &aMsg,
                                              const int aMessageId,
                                              const int aTimeout_ms);
    

    /** 
     *
     * This function is identical to previous version of
     * ReceiveSynchronousMessageReply(), \b except that this function
     * does the DataType conversion online. For example, you can call this function directly like:
     * \code
     * CDummyData dd;
     * SMessageSource ms;
     * ReceiveSynchronousMessageReply(dd, ms, 1000);
     * \endcode
     *
     * And the MaCI will take care of the conversion for you! This is
     * implemented as template function, so the converted type must
     * implement atleast the following methods: 
     * \code
     * bool DecodeFrom(gim::binbag::CBinBag *aBinBag);
     * \endcode
     *
     * \overload
     *
     * @param[out] aData        Type-converted data element output.
     * @param[out] aSource      Source information for the received message.
     * @param[in] aMessageID    MessageID to look for.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait for 
     *                          the reply to arrive.
     * @return                  'KMaCIOK' when correct reply is succesfully received.
     *                          Other values when there was an error 
     *                          (See desription of type EMaCIError)
     */
    template <class T> MaCI::EMaCIError ReceiveSynchronousMessageReply(T &aData,
                                                                 MaCI::SMessageSource &aSource,
                                                                 const int aMessageId,
                                                                 const int aTimeout_ms);


    /** Receive multiple replies from Reply queue.
     *
     * This function returns a number of message from the reply queue
     * identified by the given array of messageIDs.
     *
     * \note As the messages are returned as GIMIMessage pointers, all
     * pointers represent a dynamically allocated GIMIMessage object.
     * When you are done with the messages, you \b must manually
     * delete all returned pointers in order the free the associated
     * memory!
     *
     * \note Any Messages received before the timeout are stored on
     * the output array anyway.
     *
     * \note The Synchronous message feature must be enabled in order
     * for this to work. See function:
     * 'EnableSynchronousMessageReply()'.
     *
     * \see EnableSynchronousMessageReply
     *
     * @param[out] aGIMIMessageArray Array of GIMIMessage pointers 
     *                               containing the received messages.
     * @param[in] aMessageIDArray Array of messageIDs to wait for.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait for 
     *                          the whole operation to complete (all messages received)
     * @return                  'KMaCIOK' when all correct replies are succesfully received.
     *                          Other values when there was an error 
     *                          (See desription of type EMaCIError).
     *                          \b Note that any Messages received before the timeout
     *                          are stored on the output array anyway.
     */
    MaCI::EMaCIError ReceiveSynchronousMessageReply(std::vector<gimi::GIMIMessage *> & aGIMIMessageArray,
                                              const std::vector<int> &aMessageIDArray,
                                              const int aTimeout_ms);


    /** Receive multiple replies from Reply queue, converting to
     * correct datatype.
     *
     * This function is identical to previous version of
     * ReceiveSynchronousMessageReply(), \b except that this function
     * does the DataType conversion online. For example, you can call this function directly like:
     * \code
     * CDummyData dd;
     * SMessageSource ms;
     * ReceiveSynchronousMessageReply(dd, ms, 1000);
     * \endcode
     *
     * And the MaCI will take care of the conversion for you! This is
     * implemented as template function, so the converted type must
     * implement atleast the following methods: 
     * \code
     * bool DecodeFrom(gim::binbag::CBinBag *aBinBag);
     * \endcode
     *
     * \overload
     *
     * @param[out] aDataArray   Type-converted data element output array.
     * @param[out] aSourceArray Source information for the received message. (index matches the one of DataArray)
     * @param[in] aMessageIDArray Array of MessageIDs to look for. All of these are attempted to
     *                          receive. If all messageIDs in this array are received, the operation
     *                          completes succesfully.
     * @param[in] aTimeout_ms   Timeout in milliseconds to wait for 
     *                          all replies to arrive.
     * @return                  'KMaCIOK' when all correct replies are succesfully received.
     *                          Other values when there was an error 
     *                          (See desription of type EMaCIError).
     *                          \b Note that any Messages received before the timeout
     *                          are stored on the output array anyway.
     */
    template <class T> MaCI::EMaCIError ReceiveSynchronousMessageReply(std::vector< T > &aDataArray,
                                                                 std::vector<MaCI::SMessageSource> &aSourceArray,
                                                                 const std::vector<int> &aMessageIDArray,
                                                                 const int aTimeout_ms);
    

    /** Returns an unique messageID.
     *
     * This function returns an unique messageID for keying
     * sent/Received messages. The messageID is generated by
     * incrementing one to last get. The getter function is
     * re-entrant, so multiple threads may get unique keys without
     * conflicts.
     *
     * @return                  Unique messageID to use for 
     *                          sending/receiving replies.
     */
    inline const unsigned int GetUniqueMessageID(void);

    
    /** Enable receiving synchronous message replies.
     *
     * This function call constructs required facilities for receiving
     * message replies. MessageReply is a feature provided by MaCI
     * which is intended for RPC like calls to exchange data between
     * client and server. This call is only required on the \b
     * receiving side of replies, iow, on the side which will call the
     * 'ReceiveSynchronousMessageReply()' function. On the sending
     * side ('SendSynchronousMessageReply()') calling this function is
     * not required.
     *
     * Usual sequence using 'Synchronous replies' feature goes as follows:
     * \msc
     * Application,Client,Server,Module;
     * Application->Client [label="SendInterfaceMessage()"];
     * Client->Server [label="Message(Command)"];
     * Server->Module [label="ReceiveInterfaceMessage()"];
     * Server<-Module [label="SendSynchronousMessageReply()"];
     * Client<-Server [label="Message(Reply)"];
     * Application<-Client [label="ReceiveSynchronousMessageReply()"];
     * \endmsc
     *
     * @param[in] aAcceptBroadcasts If this is set to \b true, the
     * interface will receive replies from \b ANY source, instead of
     * binding the accepted entries to single sender (which is the
     * default action when default value \b false is used)
     *
     * @return                  'KMaCIOK' when feature is succesfully enabled.
     *                          Other values when there was problems
     *                          (See desription of type EMaCIError)
     */
    MaCI::EMaCIError EnableSynchronousMessageReply(const bool aAcceptBroadcasts = false);


    /** Disable receiving synchronous message replies.
     *
     * This function disable receiving synchronous message
     * replies. Calling this will disallow receiving replies from
     * remote hosts, thus ReceiveSynchronousMessageReply() will yield
     * an error.
     *
     * @return                  'KMaCIOK' when feature is succesfully disabled.
     *                          Other values when there was problems
     *                          (See desription of type EMaCIError)
     */
    MaCI::EMaCIError DisableSynchronousMessageReply(void);


    /** Returns true if the synchronous message replies are enabled.
     *
     * This function returns true if the Synchronous message interface
     * was previously enabled by calling function
     * 'EnableSynchronousMessageReply()'.
     *
     * @return                  'true' if the Reply receiving feature is
     *                          currently active, otherwise 'false'.
     */
    bool IsSynchronousMessageReplyEnabled(void) const;


    /** Subscribe to service using the default interface parameters.
     *
     * This function subscribes to service at currently set default
     * target, using the currently set major/minor numbers of this
     * interface. This function automatically registers the subscribed
     * major/minor type as 'Accepted' for this interface.
     *
     * @param[in] aTimeout_ms   Timeout for subscribe operation. It
     *                          defaults to 2000ms 
     *                          (+ automatic static delay)
     * @param[in] aResubscribe_ms Set GIMI resubscription time in
     *                          milliseconds. Defaults to 10000ms.
     * @return                  KMaCIOK when succesfully subscribed to
     *                          service. Otherwise appropriate EMaCIError
     *                          value is returned.
     */
    MaCI::EMaCIError SubscribeToInterface(unsigned int aTimeout_ms = 2000,
                                    unsigned int aResubscribe_ms = 10000);

    
    
    
    /** Unsubscribe a service using the default interface parameters.
     *
     * This function unsubscribes a previously subscribed service on
     * the currently set default target, using the currently set
     * major/minor numbers of this interface. This function
     * automatically unregisters the Accepted types for this
     * interface.
     *
     * @param[in] aTimeout_ms   Timeout for unsubscribe operation. It
     *                          defaults to 2000ms 
     *                          (+ automatic static delay)
     *                          service. Otherwise appropriate EMaCIError
     *                          value is returned.
     */
    MaCI::EMaCIError UnsubscribeToInterface(const unsigned int aTimeout_ms = 2000);
    

    
    /** Verify that the current default target accepts command with
     * major/minor numbers set for this interface.
     *
     * This function calls a serviceDiscovery on the current default
     * target and searches for the service major/minor pair currently
     * set for this interface.  If the pair is found from the list of
     * services and is listed as ACCEPTED service, this function
     * returns KMaCIOK.
     *
     * @return                  KMaCIOK when the current default target accepts
     *                          messages with the currently set major/minor numbers.
     *                          Otherwise appropriate EMaCIError is returned.
     */
    MaCI::EMaCIError IsServiceAcceptedOnTarget(void);
    
    
    /** Return Interface access information for specified NodeID.
     *
     * This function fetched access information for current MaCI
     * instance (identified by CMaCI::iInterfaceMajor and
     * CMaCI::iInterfaceMinor).
     * \n
     * Calling this function is functionally equal to:\n
     * \code
     * GetMaCICtrlServer()->GetAccessInfo(aAccess, iInterfaceMajor,
     *                                    iInterfaceMinor, aNodeID,
     *                                    true);
     * \endcode
     *
     * For advanced options, use the MaCICtrl* instance directly as
     * shown on the functionality example.
     *
     * \note This function requests information of local
     * authentication, so this function is probably only useful on the
     * server (driver control) side of MaCI.
     *
     * @param[out] aAccess      MaCICtrl::TAccess structure to fill with information
     * @param[in] aNodeID       NodeID to get access information for.
     * @return                  'KMaCIOK' when access was succesfully read and stored.
     *                          Other values when there was a communication 
     *                          layer error (See desription of type EMaCIError)
     */
    MaCI::EMaCIError GetInterfaceAccess(MaCI::MaCICtrl::TAccess &aAccess,
                                  const unsigned int aNodeID);


    /** Return boolean value whether specified node is allowed to
     * access this server interface.
     *
     * This function fetched access information for current MaCI
     * instance (identified by CMaCI::iInterfaceMajor and
     * CMaCI::iInterfaceMinor).
     * \n
     * Calling this function is functionally equal to:\n
     * \code
     * MaCICtrl::TAccess a;
     * GetMaCICtrlServer()->GetAccessInfo(a, iInterfaceMajor,
     *                                    iInterfaceMinor, aNodeID,
     *                                    true);
     * return a.IsAccess();
     * \endcode
     *
     * For advanced options, use the MaCICtrl* instance directly as
     * shown on the functionality example.
     *
     * \note This function requests information of local
     * authentication, so this function is probably only useful on the
     * server (driver control) side of MaCI.
     *
     * @param[in] aNodeID       NodeID to get access information for.
     * @return                  'true' when the requested NodeID is
     *                          allowed to access this interface, otherwise 
     *                          'false'. 'false' is also returned in case
     *                          of any error.
     */
    bool IsInterfaceAccess(const unsigned int aNodeID);

    
    /** Return mutable pointer to CMaCICtrlServer.
     *
     * This function returns a MUTABLE pointer to MaCI-internal MaCICtrlServer
     * instance. This instance is used for advertising Interface to the GIMnet.
     * To set MaCICtrl specific parameters, use this pointer directly, as
     * it is the master MaCICtrl instance used by this MaCI instance.
     *
     * \see CMaCICtrlServer
     *
     * @return                  Mutable pointer to CMaCICtrlServer instance.
     */
    MaCI::MaCICtrl::CMaCICtrlServer *GetMaCICtrlServer() { return iMaCICtrlServer; }


    /** Return const pointer to CMaCICtrlServer.
     *
     * This function returns a constant pointer to MaCI-internal MaCICtrlServer
     * instance. This instance is used for advertising Interface to the GIMnet.
     * To only access MaCICtrl specific parameters, use this pointer directly, as
     * it is the master MaCICtrl instance used by this MaCI instance.
     * 
     * \see CMaCICtrlServer
     *
     * @return                  Constant pointer to CMaCICtrlServer instance.
     */
    const MaCI::MaCICtrl::CMaCICtrlServer *GetMaCICtrlServer() const { return iMaCICtrlServer; }

    
    /** Return constant pointer to CMaCICtrlClient.
     *
     * This function returns a constant pointer to MaCI-internal
     * CMaCICtrlClient instance. This instance is used for accessing
     * MaCICtrl information from other MaCI-cabable nodes on the
     * GIMnet.
     *
     * \see CMaCICtrlServer
     *
     * @return                  Constant pointer to CMaCICtrlClient instance.
     */
    const MaCI::MaCICtrl::CMaCICtrlClient *GetMaCICtrlClient() const { return iMaCICtrlClient; }

    ///////////////////////////////////////////////////////////////////////////
    ////////////// Variables //////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    bool iIsInternalGIMIInstance;       ///< Is the GIMI Common pointer pointer to internal instance?
    gimi::GIMI *iGIMIPtr;               ///< Common pointer to GIMI
    int iInterfaceMajor;                ///< Interface Major number (GIMI Major number)
    int iInterfaceMinor;                ///< Interface Minor number (GIMI Minor number)
    std::string iInterfaceInstanceName; ///< Interface instance name.

    unsigned int iRedirectionBufferId; ///< GIMI Redirection buffer identifier
    std::string iDefaultTarget; ///< Default 'remote end' ( Datasource / Target )
    MaCI::MaCICtrl::SMaCISL iDefaultTargetMaCISL; ///< Default target MaCISL, if set.
    
    int iSubscriberUnsyncedCount;
    int iSubscriberUnsyncedTimeout;

    int iStaticLinkDelay; ///< Static link delay to add to all timeout values

    MaCI::MaCICtrl::CMaCICtrlServer *iMaCICtrlServer; ///< Pointer to CtrlServer instance
    MaCI::MaCICtrl::CMaCICtrlClient *iMaCICtrlClient; ///< Pointer to CtrlClient instance

    MaCI::MaCICtrl::TAuthentication iAuthenticationData; ///< Store given TAuthentication here
    MaCI::MaCICtrl::TAccess iAccessData; ///< Store received TAccess here.

    MaCI::Alarm::CAlarmServer *iAlarmServerPtr; ///< Build-in AlarmServer interface.

/*  private:
    // ReplyQueue parameters.
    int iReplyQueueRedirectionBufferId; ///< Redirection ID for replyQueue.
    bool iIsReplyQueueEnabled; ///< Is the Reply Queue enabled?
    std::map<int, gimi::GIMIMessage *> iReplyQueue; ///< Reply Queue contents.
    ownMutexHandle iReplyQueueMutex; ///< Protect access to ReplyQueue
    ownCondHandle iReplyQueueCond; ///< Condition for ReplyQueue.
    ownThreadHandle iReplyQueueWatchThread; ///< Reply Queue watcher thread. ( Had to use a thread :( )
    unsigned int iUniqueMessageIDCounter; ///< For getting unique messageIDs.
    
  private:
    volatile bool iIsActive; ///< Interface usable flag for state tracking.
    
  private:
    void InitializeInternals(void);
    void DeinitializeInternals(void);
    bool SearchReplyQueue(gimi::GIMIMessage &aMsg, const int aMessageID);
    inline void LockReplyQueue();
    inline void UnlockReplyQueue();
    inline bool WaitReplyQueue(const int aTimeout = -1);
    inline void NotifyReplyQueue();
    static int ReplyQueueWatchThread(CMaCI *aMaCIInstance);

    CMaCI(const CMaCI &)
      : iIsInternalGIMIInstance(),
        iGIMIPtr(NULL),
	iInterfaceMajor(0),
	iInterfaceMinor(0),
        iInterfaceInstanceName(),
	iRedirectionBufferId(0),
	iDefaultTarget(),
        iDefaultTargetMaCISL(),
	iStaticLinkDelay(),
        iMaCICtrlServer(),
        iMaCICtrlClient(),
        iAuthenticationData(),
        iAccessData(),
        iAlarmServerPtr(NULL),
        iReplyQueueRedirectionBufferId(),
        iIsReplyQueueEnabled(),
        iReplyQueue(),
        iReplyQueueMutex(),
        iReplyQueueCond(),
        iReplyQueueWatchThread(),
        iUniqueMessageIDCounter(),
        iIsActive() {}
    CMaCI &operator = (const CMaCI &) { return *this; }
*/
  };

  /////////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////////
  /////// Implementations for inline functions ////////////////////////////////
  /////////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////////
  
  inline bool CMaCI::IsActive(void) const {
    return iIsActive;
  }
  
  inline Alarm::CAlarmServer *CMaCI::GetAlarmServerPtr(void) const {
    return iAlarmServerPtr;
  }
  
  template <class T> EMaCIError CMaCI::ReceiveInterfaceMessage(T &aData, MaCI::SMessageSource &aSource, const int aTimeout_ms) {
    EMaCIError result;
    gimi::GIMIMessage gmsg;
    
    // Call the ReceiveMessage wrapper with timeout
    result = ReceiveInterfaceMessage(gmsg, aTimeout_ms);
    
    // If result is OK, process the msg.
    if (result == KMaCIOK && IsInterfaceAccess(gmsg.getSenderId())) {
      bool r;
      gim::binbag::CBinBag bb;
      T d;
      
      // Decode BinBag.
      r = bb.Decode(gmsg.getData(), gmsg.getDatalength());
      if (r) {
        // BinBag OK. Decode DummyData.
        r = d.DecodeFrom(&bb);
        if (r) {
          // DummyData ok. Copy to caller.
          aData.Copy(d);
          
          // Copy source info too.
          aSource = gmsg;
          
        } else {
          result = MaCI::KMaCIInvalidFormat;
          
        }
        
      } else {
        result = MaCI::KMaCIInvalidFormat;
        
      }
    } else if (result == KMaCIOK) {
      // result was KMaCIOK, so the interface access query must have
      // failed. Change error to access denied.
      result = MaCI::KMaCIAccessDenied;
    }
    
    return result;
  }

  template <class T> MaCI::EMaCIError CMaCI::ReceiveSynchronousMessageReply(T &aData,
                                                                      MaCI::SMessageSource &aSource,
                                                                      const int aMessageId,
                                                                      const int aTimeout_ms) {
    EMaCIError result;
    gimi::GIMIMessage gmsg;
    
    // Call the ReceiveMessage wrapper with timeout
    result = ReceiveSynchronousMessageReply(gmsg, aMessageId, aTimeout_ms);
    
    // If result is OK, process the msg.
    if (result == KMaCIOK) {
      bool r;
      gim::binbag::CBinBag bb;
      T d;
      
      // Decode BinBag.
      r = bb.Decode(gmsg.getData(), gmsg.getDatalength());
      if (r) {
        // BinBag OK. Decode DummyData.
        r = d.DecodeFrom(&bb);
        if (r) {
          // DummyData ok. Copy to caller.
          aData.Copy(d);
          
          // Copy source info too.
          aSource = gmsg;
          
        } else {
          result = MaCI::KMaCIInvalidFormat;
          
        }
        
      } else {
        result = MaCI::KMaCIInvalidFormat;
        
      }
    }
    
    return result; 
  }
  template <class T> MaCI::EMaCIError CMaCI::ReceiveSynchronousMessageReply(std::vector< T > &aDataArray,
                                                                      std::vector<MaCI::SMessageSource> &aSourceArray,
                                                                      const std::vector<int> &aMessageIDArray,
                                                                      const int aTimeout_ms) {
    MaCI::EMaCIError result;
    std::vector<gimi::GIMIMessage *> allMsgs;
    
    // Clear output vectors.
    aDataArray.clear();
    aSourceArray.clear();

    // Call the ReceiveMessage wrapper with timeout
    result = ReceiveSynchronousMessageReply(allMsgs, aMessageIDArray, aTimeout_ms);
    
    // If result is OK, process the msg.
    if (result == KMaCIOK) {
      bool r;

      // For all messages in replyarray
      for(EACH_IN_i(allMsgs)) {
        // Decode BinBag.
        gim::binbag::CBinBag bb;
        T d;
        r = bb.Decode((*i)->getData(), (*i)->getDatalength());
        if (r) {
          // BinBag OK. Decode DummyData.
          r = d.DecodeFrom(&bb);
          if (r) {
            // DummyData ok. Copy to caller.
            aDataArray.push_back(d);
            
            // Copy source info too.
            aSourceArray.push_back(*(*i));
          } else {
            result = KMaCIInvalidFormat;
            
          }
          
        } else {
          result = KMaCIInvalidFormat;
          
        }

        // UNconditionally delete the GIMIMessage.
        // Now, delete the GIMIMessage, no longer required, and must be deleted.
        delete *i;
        
      }
    }
    
    return result; 
  }

  inline void CMaCI::LockReplyQueue() {
    ownMutex_Lock(iReplyQueueMutex);
  }
  inline void CMaCI::UnlockReplyQueue() {
    ownMutex_Unlock(iReplyQueueMutex);
  }
  inline bool CMaCI::WaitReplyQueue(const int aTimeout) {
    return ownCond_Wait(iReplyQueueCond, iReplyQueueMutex, aTimeout) == ownStatusOK;
  }
  inline void CMaCI::NotifyReplyQueue() {
    ownCond_Broadcast(iReplyQueueCond);
  }
  inline const unsigned int CMaCI::GetUniqueMessageID(void) {
    unsigned int msgid;
    ownMutex_Lock(iReplyQueueMutex);
    msgid = ++iUniqueMessageIDCounter;
    ownMutex_Unlock(iReplyQueueMutex);
    return msgid;
  }
}

// Included AFTER MaCI, as otherwise conflicts will arise.
%{
#include "AlarmServer.hpp"
%}
